-
Notifications
You must be signed in to change notification settings - Fork 3.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ensure LMS passes correct group_id when querying content #5088
Conversation
d66db24
to
3a5dab6
Compare
@jimabramson @gwprice @andy-armstrong @cahrens please review |
Provides test cases to verify that views pass the correct `group_id` to | ||
the comments service when querying discussion topics. | ||
""" | ||
cs_call_num = -1 # by default, inspect the last call to the comments service |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like some feedback on the possible refactoring of these mixins, in particular the assertion logic. The problem is that we need to check calls to mock_request
to assert that it was/wasn't called with "group_id"
. However, the order of the calls depends on the particular view.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One way to do this that would be much less brittle would be to check the request URL instead of looking for a specific index in the list of calls. You could define cs_endpoint
instead of cs_call_num
and then do something like mock_request.call_args.filter(lambda args: args[1].endswith(self.cs_endpoint))[0]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aha! I considered that, but was thinking of matching the beginning of the URL rather than the end, which posed problems when tests would query different discussion topics. Your solution should solve that :)
@@ -119,6 +119,7 @@ def _retrieve(self, *args, **kwargs): | |||
'mark_as_read': kwargs.get('mark_as_read', True), | |||
'resp_skip': kwargs.get('response_skip'), | |||
'resp_limit': kwargs.get('response_limit'), | |||
'group_id': kwargs.get('group_id') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The group_id parameter should not be passed to the CS when retrieving a single thread
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we don't pass 'group_id'
, then any user will be able to see any thread. With my changes, 'group_id'
in this place will be the student's actual group_id.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The group_id parameter is meaningless in this comments service endpoint. The constraint needs to be enforced at a higher level (i.e. once the thread is retrieved, check its group_id against the user's group_id and return 404 if there's no match).
@gwprice thanks for the feedback. I've addressed your comments in my last commit. |
@@ -118,7 +118,7 @@ def _retrieve(self, *args, **kwargs): | |||
'user_id': kwargs.get('user_id'), | |||
'mark_as_read': kwargs.get('mark_as_read', True), | |||
'resp_skip': kwargs.get('response_skip'), | |||
'resp_limit': kwargs.get('response_limit'), | |||
'resp_limit': kwargs.get('response_limit') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove this change
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
a299e29
to
bec7564
Compare
"cohorted topic": {"id": "cohorted_topic"}, | ||
"non-cohorted topic": {"id": "non_cohorted_topic"}, | ||
"cohorted_topic": {"id": "cohorted_topic"}, | ||
"non_cohorted_topic": {"id": "non_cohorted_topic"}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are you changing these?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops... I must have thought that those were topic IDs rather than topic names.
I dislike the amount of repeated code in the mixin classes. We basically have the same set of test cases enumerated three times (without topic, with cohorted topic, and with non-cohorted topic). I see a couple of potential solutions. One would be to have something like the following:
The biggest problem I have with this approach is that the two mixin subclasses could not be used in the same TestCase. Another approach could be to use ddt to get test cases for the two different topics and then have non-topic-dependent test cases just ignore the topic parameter. This would keep the amount of code down but result in redundant tests. |
I think I'm going to go the ddt route. It doesn't make sense to me to have two test classes per semantic test case (i.e. one test class for cohorted topic and one for a non-cohorted topic). Edit see comment below |
@gwprice I think there's a limit to how much we can factor this. While the group_id scenarios are semantically the same across the three cases in terms of setup, the assertions are different between the "cohorted" and "non-cohorted" topic cases. I tried using class GroupIdAssertionMixin(object):
<define assertions>
class CohortedTopicGroupIdTestMixin(GroupIdTestMixin):
# ^ not sure what to call this one
<define test cases for "without topic" / "cohorted topic" cases using call_view()>
class NonCohortedTopicGroupIdTestMixin(GroupIdTestMixin):
<define test cases for non-cohorted topic cases using call_view()> Note that |
Right, I should have realized that the assertions limit the ability to refactor. I like your suggestion. |
@gwprice I have refactored as we discussed. Thanks again for the thorough review :) Please let me know whether or not you have any remaining concerns. |
|
||
|
||
@patch('lms.lib.comment_client.utils.requests.request') | ||
class GetThreadsGroupIdTestCase( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
get_threads is really supposed to be a module-private function, so we shouldn't write separate tests for it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should I really remove them? It feels like a bad idea not to test such an integral helper function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be adequately tested by the view tests.
@gwprice please see my latest changes |
@@ -333,6 +329,198 @@ def test_html(self, mock_request): | |||
self.assertRegexpMatches(html, r'"group_name": "student_cohort"') | |||
|
|||
|
|||
@patch('lms.lib.comment_client.utils.requests.request') | |||
class SingleThreadAccessTestCase(CohortedContentTestCase, GroupIdAssertionMixin): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does not need to inherit from GroupIdAssertionMixin
👍 |
c81e9e5
to
c597be8
Compare
👍 |
b653bd8
to
4d9517b
Compare
Ensure LMS passes correct group_id when querying content
TNL-23